/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.cobra.interfaces.implementations;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.LWPException;
import com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface;

/**
 * Connects to a remote XMLRPC server to manage files.
 * Has a corresponding COBRA-Server ServerInterface implementation: XMLRPCServerImpl,
   which is located in the com.sri.ai.lpitools.cobra.server.servers.implementations.xmlrpcserver
   package.
 * @author dabraham
 *
 */
public class RPCCOBRAInterfaceImpl implements COBRAInterface {

	private final Logger logger = Logger.getLogger(getClass().getSimpleName());
	
	private XmlRpcClient client;
	private String url;
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#setUp(java.lang.String)
	 */
	@Override
	public void setUp(String url) {
		logger.entering(getClass().getName(), "setUp");
		
		this.url = "http://" + url;
		try {
			setUpClient(this.url);
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	
    /**
     * Function to set up a client with given server url
     * @param serverURL
     * @throws MalformedURLException
     */
	private void setUpClient(String url) throws MalformedURLException {
		XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
		config.setServerURL(new URL(url));
		client = new XmlRpcClient();
		client.setConfig(config);		
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#getUsers()
	 */
	@Override
	public String getUsers() throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.getUsers", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "XMLRPCException attempting to get Users", e);
			throw new LWPException("XMLRPCException attempting to get Users, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall  != null && resultCall instanceof String){
			String returnedString = (String) resultCall;
			result = returnedString;				
		}
		
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#authenticateUser(java.lang.String, java.lang.String)
	 */
	@Override
	public String authenticateUser(String user) throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.authenticateUser", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING,"Error in AuthenticateUser ", e);
			throw new LWPException("Error in AuthenticateUser, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall  != null){
			String returnedString = (String) resultCall;
			if(!returnedString.equalsIgnoreCase("NA")){
				result = returnedString;				
			}
		}
		return result;

	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#addUser(java.lang.String)
	 */
	@Override
	public boolean saveUser(String user) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveUser", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Unable to saveUser", e);
			throw new LWPException("Unable to saveUser, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#deleteUser(java.lang.String)
	 */
	@Override
	public boolean deleteUser(String user) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.deleteUser", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "unable to deleteUser", e);
			throw new LWPException("unable to deleteUser, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#listModels(java.lang.String)
	 */
	@Override
	public String listModels(String user) throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.listModels", paramModel);
			result = checkXMLRpcStringResponse(resultCall);
		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Exception in listModels", e);
			throw new LWPException("Exception in listModels, "+ e.getMessage());
		}	
		
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#getModelByName(java.lang.String, java.lang.String)
	 */
	@Override
	public String getModelByName(String user, String modelTitle) throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);		
		paramModel.add(modelTitle);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.getModelByName", paramModel);
			result = checkXMLRpcStringResponse(resultCall);
		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "XmlRpcException trying to getModelByName", e);
			throw new LWPException("XmlRpcException trying to getModelByName, "+ e.getMessage());
		}	
		
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#listQueries(java.lang.String)
	 */
	@Override
	public String listQueries(String user) throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.listQueries", paramModel);
			result = checkXMLRpcStringResponse(resultCall);
		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "XMLRpcError trying to listQueries", e);
			throw new LWPException("XMLRpcError trying to listQueries, "+ e.getMessage());
		}	
		
		return result;

	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#listEvidences(java.lang.String)
	 */
	@Override
	public String listEvidences(String user) throws LWPException{
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.listEvidences", paramModel);
			result = checkXMLRpcStringResponse(resultCall);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "XmlRpcException trying to list evidences", e);
			throw new LWPException("XmlRpcException trying to list evidences, "+ e.getMessage());
		}	
		
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#getQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public String getQuery(String user, String queryTitle) throws LWPException {
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(queryTitle);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.getQuery", paramModel);
			result = checkXMLRpcStringResponse(resultCall);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Error calling getQuery", e);
			throw new LWPException("Error calling getQuery, "+ e.getMessage());
		}	
		
		return result;

	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#getEvidence(java.lang.String, java.lang.String)
	 */
	@Override
	public String getEvidence(String user, String evidenceTitle) throws LWPException{
		Object resultCall = null;
		String result = null;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(evidenceTitle);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.getEvidence", paramModel);
			result = checkXMLRpcStringResponse(resultCall);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Error calling getEvidence", e);
			throw new LWPException("Error calling getEvidence, "+ e.getMessage());
		}	
		
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#saveModel(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveModel(String user, String title, String model) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(title);
		paramModel.add(model);

		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveModel", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Unable to save model", e);
			throw new LWPException("Unable to save model, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#saveModelInfo(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveModelInfo(String user, String title, String model) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(title);
		paramModel.add(model);

		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveModelInfo", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Unable to saveModelInfo", e);
			throw new LWPException("Unable to saveModelInfo, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#saveModelBody(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveModelBody(String user, String title, String model) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(title);
		paramModel.add(model);

		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveModelBody", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "unable to saveModelBody", e);
			throw new LWPException("unable to saveModelBody, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}	

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#saveQuery(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveQuery(String user, String title, String query) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(title);
		paramModel.add(query);

		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveQuery", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "unable to saveQuery", e);
			throw new LWPException("unable to saveQuery, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#deleteModel(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteModel(String user, String modelName) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(modelName);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.deleteModel", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "unable to deleteModel", e);
			throw new LWPException("unable to deleteModel, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#deleteQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteQuery(String user, String queryTitle) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(queryTitle);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.deleteQuery", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "unable to deleteQuery", e);
			throw new LWPException("unable to deleteQuery, "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;

	}



	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#saveEvidences(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public boolean saveEvidences(String user, String title, String evidences) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(title);
		paramModel.add(evidences);

		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.saveEvidences", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Unable to saveEvidences", e);
			throw new LWPException("Unable to saveEvidences "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface#deleteEvidences(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteEvidences(String user, String evidencesTitle) throws LWPException {
		Object resultCall = null;
		boolean result = false;
		Vector<String> paramModel = new Vector<String>();
		paramModel.add(user);
		paramModel.add(evidencesTitle);
		try {
			//call setup remote service 
			resultCall = client.execute("COBRA.deleteEvidences", paramModel);

		} catch (XmlRpcException e) {
			logger.log(Level.WARNING, "Unable to deleteEvidences ", e);
			throw new LWPException("Unable to deleteEvidences "+ e.getMessage());
		}	
		
		//if we get something back check what the result was
		//if we get result then check what it is
		if(resultCall != null){
			boolean returnedBool = (Boolean) resultCall;
			result = returnedBool;
		}
		return result;
	}
	
	/**
	 * Method will return a String cast of the input, logging a warning if the input is not actually a String
	 * @param input
	 * @return
	 * @throws LWPException 
	 */
	private String checkXMLRpcStringResponse(Object input) throws LWPException {
		String result = null;
		if (input instanceof String) {
			result = (String) input;
		} else {
			logger.log(Level.WARNING, "XMLRpcResponse was expected to be String, but instead was " + 
					(input != null ? input.getClass() : null));
			throw new LWPException("XMLRpcResponse was expected to be String, but instead was " + 
					(input != null ? input.getClass() : null));
		}
		return result;
	}


	
}
